/**
  ******************************************************************************
  * @file    tc32l010_flash.c
  * @author  CHIPAT Application Team
  * @brief   This file provides firmware functions to manage the following
  *          functionalities of the FLASH peripheral:
  *            - FLASH Interface configuration
  *            - FLASH Memory Programming
  *            - Option Bytes Programming
  *            - Interrupts and flags management
  *
  @verbatim
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "tc32l010_flash.h"

/** @addtogroup XS32L010_StdPeriph_Driver
  * @{
  */

/* FLASH Keys */
#define RDP_Key                  ((uint32_t)0x005A00A5U)
#define FLASH_KEY1               ((uint32_t)0x5A5A5A5AU)
#define FLASH_KEY2               ((uint32_t)0xA5A5A5A5U)

#define FLASH_DPDKEY1            ((uint32_t)0x04152637U)
#define FLASH_DPDKEY2            ((uint32_t)0xFAFBFCFDU)

/* Delay definition */
#define BusyTimeout              ((uint32_t)0x00003FFFU)
#define EraseTimeout             ((uint32_t)0xFFFFFFFFU)
#define ProgramTimeout           ((uint32_t)0xFFFFFFFFU)


/**
  * @brief  Clk_1us config.
  * @param  FLASH_CLK=4M CKD_1us=0x03.
  *         FLASH_CLK=24M CKD_1us=0x17.
  * @retval None
  */
void FLASH_SetTimming(uint32_t FLASH_CLK)
{
    uint16_t ckd_1us;
    uint8_t f_clk;

    /* Check the parameters */
    assert_param(IS_FLASH_CLK(FLASH_CLK));

    f_clk = FLASH_CLK / 1000000;

    ckd_1us = f_clk  - 1;

    FLASH->TIMMING &= ~ FLASH_TIME_TIMMING;
	
    FLASH->TIMMING |= (ckd_1us & FLASH_TIME_TIMMING);
}

/**
  * @brief  Sets the code latency value.
  * @param  FLASH_Latency: specifies the FLASH Latency value.
  *          This parameter can be one of the following values:
  *            @arg FLASH_Latency_0: FLASH Zero Latency cycle(0<hclk<=24M@1.2v,0<hclk<=4M@0.9v)
  *            @arg FLASH_Latency_1: FLASH One Latency cycle(4M<hclk<=24M@0.9v)
  * @param  FLASH_Lvctl: specifies the FLASH Lvctl value.
  *            @arg FLASH_LVCTL_0: FLASH Working 1.2v voltage
  *            @arg FLASH_LVCTL_1: FLASH Working 0.9v voltage
  *
  * @retval None
  */
void FLASH_SetLatency(uint32_t FLASH_Latency, uint32_t FLASH_Lvctl)
{
    uint32_t reg;

    /* Check the parameters */
    assert_param(IS_FLASH_LATENCY(FLASH_Latency));
    assert_param(IS_FLASH_LVCTL(FLASH_Lvctl));

    /* Perform Byte access to FLASH_TIME[24] to set the Latency value */
    reg = FLASH->TIMMING;

    reg &= ~(FLASH_TIME_LATENCY | FLASH_TIME_LVCTL);

    FLASH->TIMMING = reg | FLASH_Latency | FLASH_Lvctl;
}

/**
  * @brief  Unlocks the FLASH Program Erase Controller.
  *
  * @param  None
  * 
  * @retval None
  */
void FLASH_Unlock(void)
{
    if((FLASH->CR & FLASH_CR_LOCK) == RESET)
    {
        /* Authorize the FLASH Registers access */
        FLASH->BYPASS = FLASH_KEY1;
        FLASH->BYPASS = FLASH_KEY2;
    }
}

/**
  * @brief  Locks the FLASH Program Erase Controller.
  *
  * @param  None
  * 
  * @retval None
  */
void FLASH_Lock(void)
{
    /* Set the LOCK Bit to lock the FLASH Registers access */
    FLASH->CR &= ~FLASH_CR_LOCK;
}

/**
  * @brief  enter the FLASH deep power down mode.
  *
  * @param  None
  * 
  * @retval None
  */
void FLASH_EnterDeepPowerDownMode(void)
{
    /* enter power down mode */
    FLASH->DPDKEY = FLASH_DPDKEY1;
    FLASH->DPDKEY = FLASH_DPDKEY2;
}

/**
  * @brief  exit the FLASH deep power down mode.
  *
  * @param  None
  * 
  * @retval None
  */
void FLASH_ExitDeepPowerDownMode(void)
{
    /* exit power down mode */
    FLASH->CR &= ~FLASH_CR_DPD;
}

/**
  * @brief  Checks whether the specified FLASH flag is set or not.
  *
  * @param  FLASH_FLAG: specifies the FLASH flag to check.
  *                     This parameter can be one of the following values:
  *                    - FLASH_FLAG_BSY: FLASH Busy flag
  *                    - FLASH_FLAG_RDPERR: FLASH Read protected error flag
  *                    - FLASH_FLAG_WRPERR: FLASH Write protected error flag
  *                    - FLASH_FLAG_EOP: FLASH End of Operation flag
  * 
  * @retval The new state of FLASH_FLAG (SET or RESET).
  */
FlagStatus FLASH_GetFlagStatus(uint16_t FLASH_FLAG)
{
    FlagStatus bitstatus = RESET;

    /* Check the parameters */
    assert_param(IS_FLASH_GET_FLAG(FLASH_FLAG)) ;

    if(FLASH_FLAG == FLASH_FLAG_BSY)
    {
        if((FLASH->CR & FLASH_FLAG) != (uint32_t)RESET)
        {
            bitstatus = SET;
        }
        else
        {
            bitstatus = RESET;
        }
    }
    else
    {
        if((FLASH->IFR & FLASH_FLAG) != (uint32_t)RESET)
        {
            bitstatus = SET;
        }
        else
        {
            bitstatus = RESET;
        }
    }

    /* Return the new state of FLASH_FLAG (SET or RESET) */
    return bitstatus;
}

/**
  * @brief  Clears the FLASH pending flags.
  *
  * @param  FLASH_FLAG: specifies the FLASH flags to clear.
  *                    This parameter can be any combination of the following values:
  *                    - FLASH_FLAG_RDPERR: FLASH Read error flag
  *                    - FLASH_FLAG_WRPERR: FLASH Write protected error flag
  *                    - FLASH_FLAG_EOP: FLASH End of Operation flag
  * 
  * @retval None.
  */
void FLASH_ClearFlag(uint16_t FLASH_FLAG)
{
    /* Check the parameters */
    assert_param(IS_FLASH_CLEAR_FLAG(FLASH_FLAG)) ;

    /* Clear the flags */
    FLASH->IFR &= ~FLASH_FLAG;
}

/**
  * @brief  Get the FLASH status.
  *
  * @param  None.
  * 
  * @retval FLASH_Status: The returned value can be: FLASH_BUSY,
  *                       FLASH_ERROR_PG, FLASH_ERROR_WRP or FLASH_COMPLETE
  */
FLASH_Status FLASH_GetStatus(void)
{
    uint32_t reg = FLASH->IFR;
    FLASH_Status flashstatus = FLASH_COMPLETE;

    if((FLASH->CR & FLASH_FLAG_BSY) == FLASH_FLAG_BSY)
    {
        flashstatus = FLASH_BUSY;
    }
    else
    {
        if(reg & FLASH_FLAG_WRPERR)
        {
            flashstatus = FLASH_WRPERR;

            /* Clear the flags */
            reg &= ~FLASH_FLAG_WRPERR;
        }
        else
        {
            if(reg & FLASH_FLAG_RDPERR)
            {
                flashstatus = FLASH_RDPERR;

                /* Clear the flags */
                reg &= ~FLASH_FLAG_RDPERR;
            }
            else
            {
                flashstatus = FLASH_COMPLETE;

                /* Clear the flags */
                reg &= ~FLASH_FLAG_EOP;
            }
        }

        /* Clear the flags */
        FLASH->IFR = reg;
    }
    /* Return the Flash Status */
    return flashstatus;
}

/**
  * @brief  Enables or disables the specified FLASH interrupts.
  *
  * @param  FLASH_IT: specifies the FLASH interrupt sources to be enabled or disabled.
  *                    This parameter can be any combination of the following values:
  *                       - FLASH_IT_ERR: FLASH Error Interrupt
  *                       - FLASH_IT_EOP: FLASH end of operation Interrupt
  * @param  Newstate: new state of the ReadOut Protection.
  *                    This parameter can be: ENABLE or DISABLE.
  * 
  * @retval None.
  */
void FLASH_ITConfig(uint16_t FLASH_IT, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FLASH_IT(FLASH_IT));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if(NewState != DISABLE)
    {
        /* Enable the interrupt sources */
        FLASH->CR |= FLASH_IT;
    }
    else
    {
        /* Disable the interrupt sources */
        FLASH->CR &= ~(uint32_t)FLASH_IT;
    }
}

/**
  * @brief  Waits for a Flash operation to complete or a TIMEOUT to occur.
  *
  * @param  Timeout: FLASH progamming Timeout.
  * 
  * @retval FLASH Status: The returned value can be: FLASH_BUSY,
  *                  FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_COMPLETE or
  *                  FLASH_TIMEOUT.
  */
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout)
{
    FLASH_Status status = FLASH_COMPLETE;

    /* Check for the FLASH Status */
    status = FLASH_GetStatus();

    /* Wait for a Flash operation to complete or a TIMEOUT to occur */
    while((status == FLASH_BUSY) && (Timeout != 0x00))
    {
        status = FLASH_GetStatus();
        Timeout--;
    }

    if(Timeout == 0x00 )
    {
        status = FLASH_TIMEOUT;
    }

    /* Return the operation status */
    return status;
}

/**
  * @brief  Erases a specified FLASH Sector.
  *
  * @note   If an erase and a program operations are requested simultaneously,
  *         the erase operation is performed before the program one.
  *
  * @param  Sector_Address: The Sector address to be erased.
  *
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_TIMEOUT,
  *                       FLASH_WRPERR, FLASH_ERROR_RDP or FLASH_COMPLETE.
  */
FLASH_Status FLASH_EraseSector(uint32_t Sector_Address)
{
    uint32_t reg;
    FLASH_Status status = FLASH_COMPLETE;

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(BusyTimeout);

    if(status == FLASH_COMPLETE)
    {
        reg = FLASH->CR;
        reg &= ~FLASH_CR_OP;
        FLASH->CR = reg | FLASH_OP_SECTORERASE;

        *(volatile uint32_t*)Sector_Address = 0x00;

        status = FLASH_WaitForLastOperation(BusyTimeout);
    }

    /* Return the Erase Status */
    return status;
}


/**
  * @brief  Erases FLASH Chip.
  *
  * @note   If an erase and a program operations are requested simultaneously,
  *         the erase operation is performed before the program one.
  *
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_TIMEOUT,
  *                       FLASH_WRPERR, FLASH_RDPERR or FLASH_COMPLETE.
  */
FLASH_Status FLASH_EraseChip(void)
{
    FLASH_Status status = FLASH_COMPLETE;

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(EraseTimeout);

    if(status == FLASH_COMPLETE)
    {
        FLASH->CR |= FLASH_CR_OP;

        *(volatile uint32_t*)0x08000000 = 0x00;

        /* Wait for last operation to be completed */
        status = FLASH_WaitForLastOperation(EraseTimeout);

    }

    /* Return the Erase Status */
    return status;
}

/**
  * @brief  Programs a 32-bit Data at a specified address.
  *
  * @param  Address: specifies the address to be programmed.
  *         This parameter can be any address in Program memory zone or in OTP zone.
  * @param  Data: specifies the data to be programmed.
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_TIMEOUT,
  *                       FLASH_WRPERR, FLASH_RDPERR or FLASH_COMPLETE.
  */
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
    uint32_t reg;
    FLASH_Status status = FLASH_COMPLETE;

    /* Check the parameters */
    assert_param(IS_FLASH_ADDRESS(Address));

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(ProgramTimeout);

    if(status == FLASH_COMPLETE)
    {
        reg = FLASH->CR;
        reg &= ~FLASH_CR_OP;
        FLASH->CR = reg | FLASH_OP_PROGRAM;

        *(volatile uint32_t*)(Address) = Data;

        /* Wait for last operation to be completed */
        status = FLASH_WaitForLastOperation(ProgramTimeout);

    }

    /* Return the Program Status */
    return status;
}

/**
  * @brief  Programs a 16-bit Data at a specified address.
  *
  * @param  Address: specifies the address to be programmed.
  *         This parameter can be any address in Program memory zone or in OTP zone.
  * @param  Data: specifies the data to be programmed.
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_TIMEOUT,
  *                       FLASH_WRPERR, FLASH_RDPERR or FLASH_COMPLETE.
  */
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
    uint32_t reg;
    FLASH_Status status = FLASH_COMPLETE;

    /* Check the parameters */
    assert_param(IS_FLASH_ADDRESS(Address));

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(ProgramTimeout);

    if(status == FLASH_COMPLETE)
    {
        reg = FLASH->CR;
        reg &= ~FLASH_CR_OP;
        FLASH->CR = reg | FLASH_OP_PROGRAM;

        *(volatile uint16_t*)(Address) = Data;

        /* Wait for last operation to be completed */
        status = FLASH_WaitForLastOperation(ProgramTimeout);

    }

    /* Return the Program Status */
    return status;
}

/**
  * @brief  Programs a 8-bit Data at a specified address.
  *
  * @param  Address: specifies the address to be programmed.
  *         This parameter can be any address in Program memory zone or in OTP zone.
  * @param  Data: specifies the data to be programmed.
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_TIMEOUT,
  *                       FLASH_WRPERR, FLASH_RDPERR or FLASH_COMPLETE.
  */
FLASH_Status FLASH_ProgramByte(uint32_t Address, uint8_t Data)
{
    uint32_t reg;
    FLASH_Status status = FLASH_COMPLETE;

    /* Check the parameters */
    assert_param(IS_FLASH_ADDRESS(Address));

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(ProgramTimeout);

    if(status == FLASH_COMPLETE)
    {
        reg = FLASH->CR;
        reg &= ~FLASH_CR_OP;
        FLASH->CR = reg | FLASH_OP_PROGRAM;

        *(volatile uint8_t*)(Address) = Data;

        /* Wait for last operation to be completed */
        status = FLASH_WaitForLastOperation(ProgramTimeout);

    }

    /* Return the Program Status */
    return status;
}

/**
  * @brief  Programs a sector at a specified address.
  *
  * @param  Sector_Address: specifies the address to be programmed.
  *         This parameter can be any address in Program memory zone or in OTP zone.
  * @param  Data: specifies the array data to be programmed.
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_TIMEOUT,
  *                       FLASH_WRPERR, FLASH_RDPERR or FLASH_COMPLETE.
  */
FLASH_Status FLASH_ProgramPage(uint32_t Address, uint32_t Data[])
{
    uint32_t reg;
    uint8_t i;
    FLASH_Status status = FLASH_COMPLETE;

    /* Check the parameters */
    assert_param(IS_FLASH_ADDRESS(Address));

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(ProgramTimeout);

    if(status == FLASH_COMPLETE)
    {
        reg = FLASH->CR;
        reg &= ~FLASH_CR_OP;
        FLASH->CR = reg | FLASH_OP_PROGRAM;

        for(i = 0; i < 128; i++)
        {
            *(volatile uint32_t*)(Address + 4*i) = Data[i];

            /* Wait for last operation to be completed */
            status = FLASH_WaitForLastOperation(ProgramTimeout);
        }
    }

    /* Return the Program Status */
    return status;
}

/**
  * @brief  Write protects the desired sectors.
  *
  * @param  OB_WRP: specifies the address of the pages to be write protected.
  *                  This parameter can be:
  *                  @arg OB_WRProt_Sector0_4..OB_WRProt_Sector124_127
  *                  @arg OB_WRProt_AllSectors
  * @retval FLASH Status: The returned value can be: FLASH_BUSY,
  *                  FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_COMPLETE or
  *                  FLASH_TIMEOUT.
  */
FLASH_Status FLASH_OB_EnableWRP(uint32_t OB_WRP)
{
    uint32_t reg;
    FLASH_Status status = FLASH_COMPLETE;

    /* Check the parameters */
    assert_param(IS_OB_WRP(OB_WRP));

    status = FLASH_WaitForLastOperation(BusyTimeout);

    if(status==FLASH_COMPLETE)
    {
        reg = FLASH->CR;
        reg &= ~FLASH_CR_OP;
        FLASH->CR = reg | FLASH_OP_SECTORERASE;

        OB->WRP = 0x00;

        status = FLASH_WaitForLastOperation(BusyTimeout);

        if(status==FLASH_COMPLETE)
        {
            reg = FLASH->CR;
            reg &= ~FLASH_CR_OP;
            FLASH->CR = reg | FLASH_OP_PROGRAM;

            OB->WRP = OB_WRP;

            /* Wait for last operation to be completed */
            status = FLASH_WaitForLastOperation(ProgramTimeout);
        }
    }

    /* Return the write protection operation Status */
    return status;
}

/**
  * @brief  Enables or disables the read out protection.
  *                  If the user has already programmed the other option bytes before
  *                  calling this function, he must re-program them since this
  *                  function erases all option bytes.
  *
  * @param  Newstate: new state of the ReadOut Protection.
  *                    This parameter can be: ENABLE or DISABLE.
  * @retval FLASH Status: The returned value can be: FLASH_BUSY,
  *                  FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_COMPLETE or
  *                  FLASH_TIMEOUT.
  */
FLASH_Status FLASH_OB_RDPConfig(FunctionalState NewState)
{
    uint32_t reg;
    FLASH_Status status = FLASH_COMPLETE;

    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    status = FLASH_WaitForLastOperation(BusyTimeout);

    if(status==FLASH_COMPLETE)
    {
        reg = FLASH->CR;
        reg &= ~FLASH_CR_OP;
        FLASH->CR = reg | FLASH_OP_SECTORERASE;

        OB->RDP = 0x00;

        status = FLASH_WaitForLastOperation(BusyTimeout);

        if(status==FLASH_COMPLETE)
        {
            reg = FLASH->CR;
            reg &= ~FLASH_CR_OP;
            FLASH->CR = reg | FLASH_OP_PROGRAM;

            NewState?(OB->RDP = 0x00):(OB->RDP = 0xA5);

            /* Wait for last operation to be completed */
            status = FLASH_WaitForLastOperation(ProgramTimeout);
        }
    }

    /* Return the protection operation Status */
    return status;
}

/**
  * @brief  Programs the FLASH User Option Byte.
  *
  * @param  user: the new data.
  *               This parameter can be 0x00 to 0xFF.
  * @retval FLASH Status: The returned value can be: FLASH_BUSY,
  *                  FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_COMPLETE or
  *                  FLASH_TIMEOUT.
  */
FLASH_Status FLASH_OB_UserConfig(uint8_t user)
{
    uint32_t reg;
    FLASH_Status status = FLASH_COMPLETE;

    status = FLASH_WaitForLastOperation(BusyTimeout);

    if(status==FLASH_COMPLETE)
    {
        reg = FLASH->CR;
        reg &= ~FLASH_CR_OP;
        FLASH->CR = reg | FLASH_OP_SECTORERASE;

        OB->USER = 0x00;

        status = FLASH_WaitForLastOperation(BusyTimeout);

        if(status==FLASH_COMPLETE)
        {
            reg = FLASH->CR;
            reg &= ~FLASH_CR_OP;
            FLASH->CR = reg | FLASH_OP_PROGRAM;

            OB->USER = user;

            /* Wait for last operation to be completed */
            status = FLASH_WaitForLastOperation(ProgramTimeout);
        }
    }

    /* Return the Option Byte program Status */
    return status;
}

/**
  * @brief  Programs the FLASH Boot Option Byte:
  *
  * @param  OB_BOOT: 0 from boot, 0xFF from flash.
  * 
  * @retval FLASH Status: The returned value can be: FLASH_BUSY,
  *                  FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_COMPLETE or
  *                  FLASH_TIMEOUT.
  */
FLASH_Status FLASH_OB_BOOTConfig(uint8_t OB_BOOT)
{
    uint32_t reg;
    uint16_t data = *(volatile uint16_t*)0x1FFFFE10;
    FLASH_Status status = FLASH_COMPLETE;

    status = FLASH_WaitForLastOperation(BusyTimeout);

    if(status==FLASH_COMPLETE)
    {
        reg = FLASH->CR;
        reg &= ~FLASH_CR_OP;
        FLASH->CR = reg | FLASH_OP_SECTORERASE;

        OB->BOOT = 0x00;

        status = FLASH_WaitForLastOperation(BusyTimeout);

        if(status==FLASH_COMPLETE)
        {
            reg = FLASH->CR;
            reg &= ~FLASH_CR_OP;
            FLASH->CR = reg | FLASH_OP_PROGRAM;

            //OB->BOOT = OB_BOOT;
            *(volatile uint16_t*)0x1FFFFE10 = (OB_BOOT << 8) |(data & 0xff);

            /* Wait for last operation to be completed */
            status = FLASH_WaitForLastOperation(ProgramTimeout);
        }
    }

    /* Return the Option Byte program Status */
    return status;
}

/**
  * @brief  Programs the SWD Option Byte:
  *
  * @param  Newstate: new state of the ReadOut Protection.
  *                    This parameter can be: ENABLE or DISABLE.
  * 
  * @retval FLASH Status: The returned value can be: FLASH_BUSY,
  *                  FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_COMPLETE or
  *                  FLASH_TIMEOUT.
  */
FLASH_Status FLASH_OB_SWDConfig(FunctionalState NewState)
{
    uint32_t reg;
    FLASH_Status status = FLASH_COMPLETE;

    status = FLASH_WaitForLastOperation(BusyTimeout);

    if(status==FLASH_COMPLETE)
    {
        reg = FLASH->CR;
        reg &= ~FLASH_CR_OP;
        FLASH->CR = reg | FLASH_OP_SECTORERASE;

        OB->SWD = 0x00;

        status = FLASH_WaitForLastOperation(BusyTimeout);

        if(status==FLASH_COMPLETE)
        {
            reg = FLASH->CR;
            reg &= ~FLASH_CR_OP;
            FLASH->CR = reg | FLASH_OP_PROGRAM;

            NewState?(OB->SWD = 0xFF):(OB->SWD = 0x00);

            /* Wait for last operation to be completed */
            status = FLASH_WaitForLastOperation(ProgramTimeout);
        }
    }

    /* Return the Option Byte program Status */
    return status;
}

/**
  * @brief  Get the FLASH User Option Bytes values.
  *
  * @param  None.
  * 
  * @retval user data.
  */
uint8_t FLASH_OB_GetUser(void)
{
    /* Return the User Option Byte */
    return (uint8_t)(FLASH->OPTCR >> 8);
}

/**
  * @brief  Get the FLASH Write Protection Option Bytes Register value.
  *
  * @param  None.
  * 
  * @retval write protection data.
  */
uint32_t FLASH_OB_GetWRP(void)
{
    /* Return the Falsh write protection Register value */
    return (uint32_t)(FLASH->WRPR);
}

/**
  * @brief  Checks whether the FLASH Read Out Protection Status is set or not.
  *
  * @param  None.
  * 
  * @retval FLASH ReadOut Protection Status(SET or RESET)
  */
FlagStatus FLASH_OB_GetRDP(void)
{
    FlagStatus bitstatus = RESET;

    if ((FLASH->OPTCR & FLASH_OPTCR_RDP) != (uint32_t)RESET)
    {
        bitstatus = SET;
    }
    else
    {
        bitstatus = RESET;
    }

    return bitstatus;
}

/**
  * @brief  Get the FLASH size..
  *
  * @param  None.
  * 
  * @retval 1: 64kB, 0: 32kB.
  */
uint8_t FLASH_OB_GetFlashSzie(void)
{
    uint32_t data = *(volatile uint32_t*)0x1FFFFC00;
    FlagStatus bitstatus = RESET;

    if ((data & 0x1) == (uint32_t)RESET)
    {
        bitstatus = SET;
    }
    else
    {
        bitstatus = RESET;
    }

    return bitstatus;
}

/**
  * @brief  reset option byte reload.
  *
  * @param  Newstate: new state of the ReadOut Protection.
  *                    This parameter can be: ENABLE or DISABLE.
  * 
  * @retval None.
  */
void FLASH_OB_ResetCmd(FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        RCC->RSTRCR = RCC_RSTRCR_OBLRST;
    }
    else
    {
        RCC->RSTRCR = 0;
    }
}

/************************ (C) COPYRIGHT CHIPAT *****END OF FILE****/
